今天來研究布林運算的順序,我們從下面的算式開始:
True or True and False
True
上面的算式和以下的算式相等,因為 and
比 or
優先權更高,會先進行運算:
True or (True and False)
True
下面的結果就不同了,因為我們先用括號把 or
包起來運算:
(True or True) and False
False
假設我們有以下的算式:
a = 10
b = 2
if a/b > 2:
print('a is at least double b')
a is at least double b
看起來一切OK,但假如 b = 0,就會遇到問題了:
a = 10
b = 0
if a/b > 2:
print('a is at least double b')
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
/Users/maotingyang/Downloads/Booleans - Precedence and Short-Circuiting.ipynb Cell 11 in <cell line: 4>()
<a href='vscode-notebook-cell:/Users/maotingyang/Downloads/Booleans%20-%20Precedence%20and%20Short-Circuiting.ipynb#X11sZmlsZQ%3D%3D?line=0'>1</a> a = 10
<a href='vscode-notebook-cell:/Users/maotingyang/Downloads/Booleans%20-%20Precedence%20and%20Short-Circuiting.ipynb#X11sZmlsZQ%3D%3D?line=1'>2</a> b = 0
----> <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/Booleans%20-%20Precedence%20and%20Short-Circuiting.ipynb#X11sZmlsZQ%3D%3D?line=3'>4</a> if a/b > 2:
<a href='vscode-notebook-cell:/Users/maotingyang/Downloads/Booleans%20-%20Precedence%20and%20Short-Circuiting.ipynb#X11sZmlsZQ%3D%3D?line=4'>5</a> print('a is at least double b')
ZeroDivisionError: division by zero
因為 0 是不能當分母的。
這時候我們可以運用「短路」,也就是當 and
左邊不成立時,右邊不會再運算下去。就跟一個串連的電路一樣,當遇到第一個開關斷開,不用管第二個開關的狀態,電路都是不通的:
a = 10
b = 0
if b and a/b > 2:
print('a is at least double b')
以上的寫法就可以避開分母為 0 的錯誤了。
再來看一個常見的情況,我們從資料庫撈出字串,其中可能有 None
也可能有空字串,怎麼處理?
我們先 import 一個好用的 module:string
import string
help(string)
Help on module string:
NAME
string - A collection of string constants.
DESCRIPTION
Public module variables:
whitespace -- a string containing all ASCII whitespace
ascii_lowercase -- a string containing all ASCII lowercase letters
ascii_uppercase -- a string containing all ASCII uppercase letters
ascii_letters -- a string containing all ASCII letters
digits -- a string containing all ASCII decimal digits
hexdigits -- a string containing all ASCII hexadecimal digits
octdigits -- a string containing all ASCII octal digits
punctuation -- a string containing all ASCII punctuation characters
printable -- a string containing all ASCII characters considered printable
CLASSES
builtins.object
Formatter
Template
class Formatter(builtins.object)
| Methods defined here:
|
| check_unused_args(self, used_args, args, kwargs)
|
| convert_field(self, value, conversion)
|
| format(self, format_string, /, *args, **kwargs)
|
| format_field(self, value, format_spec)
|
| get_field(self, field_name, args, kwargs)
| # given a field_name, find the object it references.
| # field_name: the field being looked up, e.g. "0.name"
| # or "lookup[3]"
| # used_args: a set of which args have been used
| # args, kwargs: as passed in to vformat
|
| get_value(self, key, args, kwargs)
|
| parse(self, format_string)
| # returns an iterable that contains tuples of the form:
| # (literal_text, field_name, format_spec, conversion)
| # literal_text can be zero length
| # field_name can be None, in which case there's no
| # object to format and output
| # if field_name is not None, it is looked up, formatted
| # with format_spec and conversion and then used
|
| vformat(self, format_string, args, kwargs)
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
class Template(builtins.object)
| Template(template)
|
| A string class for supporting $-substitutions.
|
| Methods defined here:
|
| __init__(self, template)
| Initialize self. See help(type(self)) for accurate signature.
|
| safe_substitute(self, mapping={}, /, **kws)
|
| substitute(self, mapping={}, /, **kws)
|
| ----------------------------------------------------------------------
| Class methods defined here:
|
| __init_subclass__() from builtins.type
| This method is called when a class is subclassed.
|
| The default implementation does nothing. It may be
| overridden to extend subclasses.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| braceidpattern = None
|
| delimiter = '$'
|
| flags = re.IGNORECASE
|
| idpattern = '(?a:[_a-z][_a-z0-9]*)'
|
| pattern = re.compile('\n \\$(?:\n ...identifie...
FUNCTIONS
capwords(s, sep=None)
capwords(s [,sep]) -> string
Split the argument into words using split, capitalize each
word using capitalize, and join the capitalized words using
join. If the optional second argument sep is absent or None,
runs of whitespace characters are replaced by a single space
and leading and trailing whitespace are removed, otherwise
sep is used to split and join the words.
DATA
__all__ = ['ascii_letters', 'ascii_lowercase', 'ascii_uppercase', 'cap...
ascii_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz'
ascii_uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
digits = '0123456789'
hexdigits = '0123456789abcdefABCDEF'
octdigits = '01234567'
printable = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTU...
punctuation = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
whitespace = ' \t\n\r\x0b\x0c'
FILE
/opt/homebrew/Cellar/python@3.10/3.10.6_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/string.py
string.digits
'0123456789'
string.ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
我們拿到很常用的「數字大全」和「英文字母大全」,用它們來寫程式94開心:
name = ''
if name[0] in string.digits:
print('Name cannot start with a digit!')
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
/Users/maotingyang/Downloads/Booleans - Precedence and Short-Circuiting.ipynb Cell 20 in <cell line: 2>()
<a href='vscode-notebook-cell:/Users/maotingyang/Downloads/Booleans%20-%20Precedence%20and%20Short-Circuiting.ipynb#X21sZmlsZQ%3D%3D?line=0'>1</a> name = ''
----> <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/Booleans%20-%20Precedence%20and%20Short-Circuiting.ipynb#X21sZmlsZQ%3D%3D?line=1'>2</a> if name[0] in string.digits:
<a href='vscode-notebook-cell:/Users/maotingyang/Downloads/Booleans%20-%20Precedence%20and%20Short-Circuiting.ipynb#X21sZmlsZQ%3D%3D?line=2'>3</a> print('Name cannot start with a digit!')
IndexError: string index out of range
啊⋯⋯遇到問題了,對空字串取 indexing 會報錯,怎麼辦呢?
善用「短路」的技巧:
name = ''
if name and name[0] in string.digits:
print('Name cannot start with a digit!')
name = None
if name and name[0] in string.digits:
print('Name cannot start with a digit!')
name = 'Bob'
if name and name[0] in string.digits:
print('Name cannot start with a digit!')
name = '1Bob'
if name and name[0] in string.digits:
print('Name cannot start with a digit!')
Name cannot start with a digit!
Python村又度過了和平的一天,感謝讀者們的努力,我們明天見~
參考:Python 3: Deep Dive (Part 1 - Functional)